package utils

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"io/ioutil"
	"net"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
)

// 16进制的字符表示和二进制字节表示互转
var (
	Bin2Hex = hex.EncodeToString
	Hex2Bin = hex.DecodeString
)

// convert GBK to UTF-8
func DecodeGBK(words []byte) []byte {
	dec := simplifiedchinese.GBK.NewDecoder()
	reader := transform.NewReader(bytes.NewReader(words), dec)
	output, _ := ioutil.ReadAll(reader)
	return output
}

// convert UTF-8 to GBK
func EncodeGBK(words []byte) []byte {
	enc := simplifiedchinese.GBK.NewEncoder()
	reader := transform.NewReader(bytes.NewReader(words), enc)
	output, _ := ioutil.ReadAll(reader)
	return output
}

func FirstByte(data []byte) byte {
	if len(data) >= 1 {
		return data[0]
	}
	return 0x00
}

func ReverseBytes(data []byte) []byte {
	size := len(data)
	for i := 0; i < size/2; i++ {
		data[i], data[size-i-1] = data[size-i-1], data[i]
	}
	return data
}

func IsZeroBytes(data []byte) bool {
	if data == nil {
		return true
	}
	zero := bytes.Repeat([]byte{0x00}, len(data))
	return bytes.Compare(data, zero) == 0
}

func PutUint32(n int, bom bool) []byte {
	num, data := uint32(n), make([]byte, 4)
	if bom {
		binary.BigEndian.PutUint32(data, num)
	} else {
		binary.LittleEndian.PutUint32(data, num)
	}
	return data
}

func Uint64(data []byte, bom bool) uint64 {
	size := len(data)
	if size > 8 {
		data = data[:8]
	}
	if bom {
		if size < 8 {
			zero := bytes.Repeat([]byte{0x00}, 8-size)
			data = append(zero, data...)
		}
		return binary.BigEndian.Uint64(data)
	} else {
		if size < 8 {
			zero := bytes.Repeat([]byte{0x00}, 8-size)
			data = append(data, zero...)
		}
		return binary.LittleEndian.Uint64(data)
	}
}

func BomUint64(data []byte) uint64 {
	return Uint64(data, true)
}

func LomUint64(data []byte) uint64 {
	return Uint64(data, false)
}

func Compare(a, b []byte, bom bool) int {
	if bom {
		return bytes.Compare(a, b)
	} else {
		return LomCompare(a, b)
	}
}

func LomCompare(a, b []byte) int {
	aSize, bSize := len(a), len(b)
	if aSize > bSize && !IsZeroBytes(a[bSize:]) {
		return 1
	} else if aSize < bSize && !IsZeroBytes(b[aSize:]) {
		return -1
	}
	for i := aSize - 1; i >= 0; i-- {
		if a[i] > b[i] {
			return 1
		} else if a[i] < b[i] {
			return -1
		}
	}
	return 0
}

func Ip2Bytes(ip string) []byte {
	return net.ParseIP(ip).To4()
}
